//
//  Api.swift
//  网络请求接口包装类
//  对外部提供一个和框架无关的接口
//
//  Created by smile on 2019/6/8.
//  Copyright © 2019 ixuea. All rights reserved.
//

import Foundation

//导入响应式编程框架
import RxSwift

//导入JSON解析框架
import HandyJSON

//导入网络框架
import Moya

class Api {
    
    /// 单例设计模式
    /// 饿汉式单例
    static let shared = Api()
    
    /// MoyaProvider
    private let provider:MoyaProvider<Service>!
    
    /// 私有构造方法
    private init() {
        //插件列表
        var plugins:[PluginType] = []
        
        if DEBUG {
            //表示当前是调试模式
            //添加网络请求日志插件
            plugins.append(NetworkLoggerPlugin())
        }
        
        //网络请求加载对话框
        let networkActivityPlugin = NetworkActivityPlugin { (changeType, targetType) in
            
            //changeType类型是NetworkActivityChangeType
            //通过它能监听到开始请求和结束请求
            
            //targetType类型是TargetType
            //就是我们这里的service
            //通过它能判断是那个请求
            
            
            if changeType == .began {
                //开始请求
                
                let targetType = targetType as! Service
                
                switch targetType {
                case .sheetDetail, .login:
                    DispatchQueue.main.async {
                        //切换到主线程
                        ToastUtil.showLoading()
                    }

                default:
                    break
                }
            }else {
                //结束请求
                
                DispatchQueue.main.async {
                    //切换到主线程
                    ToastUtil.hideLoading()
                }
            }
            
            
        }
        
        plugins.append(networkActivityPlugin)
        
        //网络请求签名加密插件
        plugins.append(NetworkPlugin())
        
        /// 创建Request的闭包
        /// 在这里能修改body
        /// 修改请求头
        let requestClosure={ (endpoint:Endpoint,closure:MoyaProvider.RequestResultClosure) in
            do {
                //获取到request
                var request:URLRequest = try endpoint.urlRequest()
                
                //处理request
                //主要是实现参数签名和加密
                let url = request.url!.absoluteString
                let method = request.httpMethod!
                
                print("Api requestClosure:\(url),\(method)")
                
                //处理接口参数
                
                //判断出需要添加签名的接口
                if url.hasSuffix("v2/orders") && method.hasSuffix("POST") {
                    //该接口需要添加参数签名到请求头
                    
                    //将body转为字符串
                    let bodyString=String(data: request.httpBody!, encoding: .utf8)!
                    
                    //计算签名
                    let sign=DigestUtil.sha1(bodyString)
                    
                    //添加到请求头
                    request.allHTTPHeaderFields!["Sign"]=sign
                    
                    print("Api requestClosure sign param succes:\(url),\(method)")
                }else if url.hasSuffix("v3/orders") && method.hasSuffix("POST") {
                    //该接口需要参数加密
                    
                    //将body转为字符串
                    let bodyString=String(data: request.httpBody!, encoding: .utf8)!
                    
                    //将参数加密
                    let encryptBodyString=DigestUtil.encrypAES(bodyString)!
                    
                    //重新创建body
                    let newBodyData=encryptBodyString.data(using: .utf8)
                    
                    //设置到request
                    request.httpBody=newBodyData
                    
                    print("Api requestClosure encrypt param success:\(url),\(method)")
                }
                
                //end 处理request
                
                //回调成功
                closure(.success(request))
            } catch MoyaError.requestMapping(let url) {
                closure(.failure(MoyaError.requestMapping(url)))
            }catch MoyaError.parameterEncoding(let error){
                closure(.failure(MoyaError.parameterEncoding(error)))
            }catch{
                closure(.failure(MoyaError.underlying(error, nil)))
            }
        }

        provider = MoyaProvider<Service>(requestClosure:requestClosure, plugins: plugins)
    }
    
    /// 歌单列表
    ///
    /// - Returns: <#return value description#>
    func sheets() -> Observable<ListResponse<Sheet>?> {
        return provider
            .rx
            .request(.sheets)
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(ListResponse<Sheet>.self)
    }
    
    /// 歌单详情
    ///
    /// - Parameter id: <#id description#>
    /// - Returns: <#return value description#>
    func sheetDetail(id:String) -> Observable<DetailResponse<Sheet>?> {
        return provider
            .rx
            .request(.sheetDetail(id: id))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(DetailResponse<Sheet>.self)
    }
    
    /// 获取用户创建的歌单
    ///
    /// - Parameter id: <#id description#>
    /// - Returns: <#return value description#>
    func createSheets(_ id:String) -> Observable<ListResponse<Sheet>?> {
        return provider.rx.request(.createSheets(id: id)).filterSuccessfulStatusCodes().asObservable().mapString().mapObject(ListResponse<Sheet>.self)
    }
    
    /// 获取用户收藏的歌单
    ///
    /// - Parameter id: <#id description#>
    /// - Returns: <#return value description#>
    func collectSheets(_ id:String) -> Observable<ListResponse<Sheet>?> {
        return provider.rx.request(.collectSheets(id: id)).filterSuccessfulStatusCodes().asObservable().mapString().mapObject(ListResponse<Sheet>.self)
    }
    
    /// 创建歌单
    ///
    /// - Parameter title: <#title description#>
    /// - Returns: <#return value description#>
    func createSheet(_ title:String) -> Observable<DetailResponse<BaseModel>?> {
        return provider.rx.request(.createSheet(title: title)).filterSuccessfulStatusCodes().asObservable().mapString().mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 创建用户（注册）
    ///
    /// - Parameters:
    ///   - avatar: 头像
    ///   - nickname: 昵称
    ///   - phone: 手机号
    ///   - email: 邮箱
    ///   - password: 密码
    ///   - qq_id: qq第三方登录后的Id
    ///   - weibo_id: 微博第三方登录后的Id
    /// - Returns: <#return value description#>
    func createUser(avatar:String?=nil,nickname:String,phone:String,email:String,password:String,qq_id:String?=nil,weibo_id:String?=nil,wechat_id:String?=nil) -> Observable<DetailResponse<BaseModel>?> {
        return provider
            .rx
            .request(.createUser(avatar: avatar, nickname: nickname, phone: phone, email: email, password: password, qq_id: qq_id, weibo_id: weibo_id,wechat_id:wechat_id))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 更新用户
    ///
    /// - Parameters:
    ///   - id: <#id description#>
    ///   - nickname: <#nickname description#>
    ///   - avatar: <#avatar description#>
    ///   - description: <#description description#>
    ///   - gender: <#gender description#>
    ///   - birthday: <#birthday description#>
    ///   - province: <#province description#>
    ///   - province_code: <#province_code description#>
    ///   - city: <#city description#>
    ///   - city_code: <#city_code description#>
    ///   - area: <#area description#>
    ///   - area_code: <#area_code description#>
    /// - Returns: <#return value description#>
    func updateUser(id:String,nickname:String?,avatar:String?,description:String?,gender:Int?,birthday:String?,province:String?,province_code:String?,city:String?,city_code:String?,area:String?,area_code:String?) -> Observable<DetailResponse<BaseModel>?> {
        return provider
            .rx
            .request(.updateUser(id:id,nickname:nickname,avatar:avatar,description:description,gender:gender,birthday:birthday,province:province,province_code:province_code,city:city,city_code:city_code,area:area,area_code:area_code))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(DetailResponse<BaseModel>.self)
    }
    
    
    /// 用户详情
    ///
    /// - Parameters:
    ///   - id: <#id description#>
    ///   - nickname: <#nickname description#>
    /// - Returns: <#return value description#>
    func userDetail(id:String,nickname:String?=nil) -> Observable<DetailResponse<User>?> {
        return provider.rx.request(.userDetail(id:id, nickname: nickname)).filterSuccessfulStatusCodes().asObservable().mapString().mapObject(DetailResponse<User>.self)
    }
    
    /// 绑定第三方账号
    ///
    /// - Parameters:
    ///   - account: 第三方平台Id
    ///   - platform: 平台类型；取值在常量文件中
    /// - Returns: <#return value description#>
    func bindAccount(_ account:String,_ platform:Int) -> Observable<DetailResponse<BaseModel>?> {
        return provider.rx.request(.bindAccount(account:account,platform:platform)).filterSuccessfulStatusCodes().asObservable().mapString().mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 解绑第三方账户
    ///
    /// - Parameter platform: <#platform description#>
    /// - Returns: <#return value description#>
    func unbindAccount(_ platform:Int) -> Observable<DetailResponse<BaseModel>?> {
        return provider.rx.request(.unbindAccount(platform:platform)).filterSuccessfulStatusCodes().asObservable().mapString().mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 登录
    ///
    /// - Parameters:
    ///   - phone: 手机号
    ///   - email: 邮件
    ///   - password: 密码
    ///   - qq_id: qq第三方登录后Id
    ///   - weibo_id: 微博第三方登录后Id
    /// - Returns: <#return value description#>
    func login(phone:String?=nil,email:String?=nil,password:String?=nil,qq_id:String?=nil,weibo_id:String?=nil,wechat_id:String?=nil) -> Observable<DetailResponse<Session>?> {
        return provider
            .rx
            .request(.login(phone: phone, email: email, password: password, qq_id: qq_id, weibo_id: weibo_id,wechat_id:wechat_id))
            .filterSuccessfulStatusCodes()
            .mapString()
            .asObservable()
            .mapObject(DetailResponse<Session>.self)
    }
    
    /// 重置密码
    ///
    /// - Parameters:
    ///   - phone: 手机号
    ///   - email: 邮箱
    ///   - code: 验证码
    ///   - password: 新密码
    /// - Returns: <#return value description#>
    func resetPassword(phone:String?,email:String?,code:String,password:String) -> Observable<DetailResponse<BaseModel>?> {
        return provider
            .rx
            .request(.resetPassword(phone: phone, email: email, code: code, password: password))
            .filterSuccessfulStatusCodes()
            .mapString()
            .asObservable()
            .mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 关注用户
    ///
    /// - Parameter id: <#id description#>
    /// - Returns: <#return value description#>
    func follow(_ id:String) -> Observable<DetailResponse<BaseModel>?> {
        return provider.rx.request(.follow(id: id)).filterSuccessfulStatusCodes().mapString().asObservable().mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 取消关注
    ///
    /// - Parameter id: <#id description#>
    /// - Returns: <#return value description#>
    func deleteFollow(_ id:String) -> Observable<DetailResponse<BaseModel>?> {
        return provider.rx.request(.deleteFollow(id: id)).filterSuccessfulStatusCodes().mapString().asObservable().mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 发送验证码
    ///
    /// - Parameter phone: <#phone description#>
    /// - Returns: <#return value description#>
    func sendSMSCode(phone:String) -> Observable<DetailResponse<BaseModel>?> {
        return provider
            .rx
            .request(.sendSMSCode(phone: phone))
            .filterSuccessfulStatusCodes()
            .mapString()
            .asObservable()
            .mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 发送邮件验证码
    ///
    /// - Parameter email: <#email description#>
    /// - Returns: <#return value description#>
    func sendEmailCode(email:String) -> Observable<DetailResponse<BaseModel>?> {
        return provider
            .rx
            .request(.sendEmailCode(email: email))
            .filterSuccessfulStatusCodes()
            .mapString()
            .asObservable()
            .mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 广告列表
    ///
    /// - Returns: <#return value description#>
    func ads() -> Observable<ListResponse<Ad>?> {
        return provider
            .rx
            .request(.ads)
            .filterSuccessfulStatusCodes()
            .mapString().asObservable()
            .mapObject(ListResponse<Ad>.self)
    }
    
    /// 单曲列表
    ///
    /// - Returns: <#return value description#>
    func songs() -> Observable<ListResponse<Song>?> {
        return provider
            .rx
            .request(.songs)
            .filterSuccessfulStatusCodes()
            .mapString()
            .asObservable()
            .mapObject(ListResponse<Song>.self)
    }
    
    /// 歌曲详情
    ///
    /// - Parameter id: <#id description#>
    /// - Returns: <#return value description#>
    func songDetail(_ id:String) -> Observable<DetailResponse<Song>?> {
        return provider
            .rx
            .request(.songDetail(id: id))
            .filterSuccessfulStatusCodes()
            .mapString()
            .asObservable()
            .mapObject(DetailResponse<Song>.self)
    }
    
    /// 收藏歌单
    ///
    /// - Parameter id: <#id description#>
    /// - Returns: <#return value description#>
    func collect(_ id:String) -> Observable<DetailResponse<BaseModel>?> {
     return provider
        .rx
        .request(.collect(id: id))
        .filterSuccessfulStatusCodes()
        .asObservable()
        .mapString()
        .mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 取消收藏歌单
    ///
    /// - Parameter id: <#id description#>
    /// - Returns: <#return value description#>
    func deleteCollect(_ id:String) -> Observable<DetailResponse<BaseModel>?> {
        return provider
        .rx
        .request(.deleteCollect(id: id))
        .filterSuccessfulStatusCodes()
        .asObservable()
        .mapString()
        .mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 评论列表
    ///
    /// - Returns: <#return value description#>
    func comments(sheet_id:String?=nil,order:Int=ORDER_NEW,page:Int=1) -> Observable<ListResponse<Comment>?> {
        return provider
            .rx
            .request(.comments(sheet_id: sheet_id, order: order, page: page))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(ListResponse<Comment>.self)
    }
    
    /// 创建评论
    ///
    /// - Parameters:
    ///   - content: <#content description#>
    ///   - sheet_id: <#sheet_id description#>
    ///   - parent_id: <#parent_id description#>
    /// - Returns: <#return value description#>
    func createComment(content:String,sheet_id:String?,parent_id:String?) -> Observable<DetailResponse<BaseModel>?> {
        return provider
            .rx
            .request(.createComment(content: content, sheet_id: sheet_id, parent_id: parent_id))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 评论点赞
    ///
    /// - Parameter comment_id: <#comment_id description#>
    /// - Returns: <#return value description#>
    func like(_ comment_id:String) -> Observable<DetailResponse<BaseModel>?> {
        return provider
            .rx
            .request(.like(comment_id: comment_id))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 取消评论点赞
    ///
    /// - Parameter id: <#id description#>
    /// - Returns: <#return value description#>
    func deleleLike(_ id:String) -> Observable<DetailResponse<BaseModel>?> {
        return provider
        .rx
        .request(.deleteLike(id: id))
        .filterSuccessfulStatusCodes()
        .asObservable()
        .mapString()
        .mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 话题列表
    ///
    /// - Returns: <#return value description#>
    func topics() -> Observable<ListResponse<Topic>?> {
        return provider
        .rx
        .request(.topics)
        .filterSuccessfulStatusCodes()
        .asObservable()
        .mapString()
        .mapObject(ListResponse<Topic>.self)
    }
    
    /// 好友列表
    ///
    /// - Parameter id: 用户Id
    /// - Returns: <#return value description#>
    func friends(_ id:String) -> Observable<ListResponse<User>?> {
        return provider.rx
        .request(.friends(id: id))
        .filterSuccessfulStatusCodes()
        .asObservable()
        .mapString()
        .mapObject(ListResponse<User>.self)
    }
    
    /// 粉丝列表
    ///
    /// - Parameter id: <#id description#>
    /// - Returns: <#return value description#>
    func fans(_ id:String) -> Observable<ListResponse<User>?> {
        return provider
            .rx
            .request(.fans(id: id))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(ListResponse<User>.self)
    }
    
    /// 视频列表
    ///
    /// - Returns: <#return value description#>
    func videos() -> Observable<ListResponse<Video>?> {
        return provider.rx.request(.videos).filterSuccessfulStatusCodes().asObservable().mapString().mapObject(ListResponse<Video>.self)
    }
    
    /// 视频详情
    ///
    /// - Parameter id: <#id description#>
    /// - Returns: <#return value description#>
    func videoDetail(_ id:String) -> Observable<DetailResponse<Video>?> {
        return provider.rx.request(.videoDetail(id: id)).filterSuccessfulStatusCodes().asObservable().mapString().mapObject(DetailResponse<Video>.self)
    }
    
    /// 动态列表
    ///
    /// - Returns: <#return value description#>
    func feeds() -> Observable<ListResponse<Feed>?> {
        return provider.rx.request(.feeds).filterSuccessfulStatusCodes().asObservable().mapString().mapObject(ListResponse<Feed>.self)
    }
    
    /// 创建动态
    ///
    /// - Parameter content: <#content description#>
    /// - Returns: <#return value description#>
    func createFeed(content:String,province:String?,city:String?,longitude:Double?,latitude:Double?,images:[Dictionary<String,String>]?) -> Observable<DetailResponse<BaseModel>?> {
        return provider.rx.request(.createFeed(content: content,province:province,city:city,longitude:longitude,latitude:latitude,images:images)).filterSuccessfulStatusCodes().asObservable().mapString().mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 搜索用户
    ///
    /// - Parameter query: <#query description#>
    /// - Returns: <#return value description#>
    func searchUsers(_ query:String) -> Observable<ListResponse<User>?> {
        return provider
            .rx
            .request(.searchUsers(query: query))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(ListResponse<User>.self)
    }
    
    /// 搜索歌单
    ///
    /// - Parameter query: <#query description#>
    /// - Returns: <#return value description#>
    func searchSheets(_ query:String) -> Observable<ListResponse<Sheet>?> {
        return provider
            .rx
            .request(.searchSheets(query: query))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(ListResponse<Sheet>.self)
    }
    
    /// 搜索建议
    ///
    /// - Parameter query: <#query description#>
    /// - Returns: <#return value description#>
    func searchSuggests(_ query:String) -> Observable<DetailResponse<Suggest>?> {
        return provider
            .rx
            .request(.searchSuggests(query: query))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(DetailResponse<Suggest>.self)
    }
    
    /// 商品列表
    ///
    /// - Returns: <#return value description#>
    func shops() -> Observable<ListResponse<Book>?> {
        return provider
            .rx
            .request(.shops)
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(ListResponse<Book>.self)
    }
    
    /// 商品详情
    ///
    /// - Parameter id: <#id description#>
    /// - Returns: <#return value description#>
    func shopDetail(_ id:String) -> Observable<DetailResponse<Book>?> {
        return provider
            .rx
            .request(.shopDetail(id: id))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(DetailResponse<Book>.self)
    }
    
    /// 创建订单
    ///
    /// - Parameter bookId: <#bookId description#>
    /// - Returns: <#return value description#>
    func createOrder(_ bookId:String) -> Observable<DetailResponse<BaseModel>?> {
        return provider
            .rx
            .request(.createOrder(book_id: bookId, source: Order.Source.ios.rawValue))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 订单详情
    ///
    /// - Parameter id: <#id description#>
    /// - Returns: <#return value description#>
    func orderDetail(_ id:String) -> Observable<DetailResponse<Order>?> {
        return provider
            .rx
            .request(.orderDetail(id: id))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(DetailResponse<Order>.self)
    }
    
    /// 订单列表
    ///
    /// - Returns: <#return value description#>
    func orders() -> Observable<ListResponse<Order>?> {
        return provider
            .rx
            .request(.orders)
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(ListResponse<Order>.self)
    }
    
    /// 订单列表V2（响应签名）
    ///
    /// - Returns: <#return value description#>
    func ordersV2() -> Observable<ListResponse<Order>?> {
        return provider
            .rx
            .request(.ordersV2)
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(ListResponse<Order>.self)
    }
    
    /// 创建订单V2（参数签名）
    ///
    /// - Parameter bookId: <#bookId description#>
    /// - Returns: <#return value description#>
    func createOrderV2(_ bookId:String) -> Observable<DetailResponse<BaseModel>?> {
        return provider
            .rx
            .request(.createOrderV2(book_id: bookId, source: Order.Source.ios.rawValue))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 订单列表V3（响应加密）
    ///
    /// - Returns: <#return value description#>
    func orderV3() -> Observable<ListResponse<Order>?> {
        return provider.rx.request(.ordersV3).filterSuccessfulStatusCodes().asObservable().mapString().mapObject(ListResponse<Order>.self)
    }
    
    /// 创建订单V3（参数加密）
    ///
    /// - Parameter bookId: <#bookId description#>
    /// - Returns: <#return value description#>
    func createOrderV3(_ bookId:String) -> Observable<DetailResponse<BaseModel>?> {
        return provider.rx.request(.createOrderV3(book_id: bookId, source: Order.Source.ios.rawValue)).filterSuccessfulStatusCodes().asObservable().mapString().mapObject(DetailResponse<BaseModel>.self)
    }
    
    /// 获取订单支付参数
    ///
    /// - Parameters:
    ///   - id: <#id description#>
    ///   - channel: <#channel description#>
    /// - Returns: <#return value description#>
    func orderPay(_ id:String,_ channel:Int) -> Observable<DetailResponse<Pay>?> {
        return provider
            .rx
            .request(.orderPay(id: id, channel: channel, origin: Order.Source.ios.rawValue))
            .filterSuccessfulStatusCodes()
            .asObservable()
            .mapString()
            .mapObject(DetailResponse<Pay>.self)
    }
}
